#ifndef PORRIDGEDB_H
#define PORRIDGEDB_H

//main database interaction logic

#include <boost/lexical_cast.hpp>

#include "indexator.h"

namespace Porridge
{

class PorridgeDB
{
    std::string m_connectionInfo;
    std::string m_newSessionQuery;
    std::string m_tableID;
    std::string m_setDBSizeLimitQuery;

    size_t maxBufferSize;

    PGconn * m_connection;
    
    bool queryFailed(const std::string & query, bool result = false) const;
    void logConnectionError(const std::string & errorMessage) const;
    void logError(const std::string & errorMessage) const;
    
    Indexator m_indexator;

protected:
    PorridgeDB(const PorridgeDB&);
    PorridgeDB& operator =(const PorridgeDB&);
    
public:
    PorridgeDB() : m_connection(NULL){}
    ~PorridgeDB();

    //init internal data
    void setConnetctionInfo(const std::string & connectionInfo);
    void setQueryThreadLimit(size_t limit);
    void setNewSessionQuery(const std::string & query);
    void setDBSizeLimitQuery(const std::string & query);
    void setMaxBufferSize(size_t size);
    template<typename InputIterator>
    void setProcessingQueries(InputIterator first, InputIterator last);
    void appendProcessingQuery(const std::string & query);

    //real work with PostgreSQL
    bool connect();
    size_t startSession();
    bool setDBSizeLimit(long dbSizeLimit);
    bool tableBegin(const std::string & tableName) const;
    //deprecated, use stream operator
    template<typename ForwardIterator>
    bool writeTable(ForwardIterator first,
                    ForwardIterator last) const;
    template<typename ForwardIterator>
    bool writeTable(const std::string & tableName,
                    ForwardIterator first,
                    ForwardIterator last) const;
    friend PorridgeDB& operator<<(PorridgeDB& out, const std::string & data);
    bool tableEnd() const;
    void write(const char * data, size_t length) const;
    void createIndexes();
};

template<typename ForwardIterator>
bool PorridgeDB::writeTable(const std::string & tableName,
                            ForwardIterator first,
                            ForwardIterator last) const
{
    tableBegin(tableName);
    writeTable(first, last);
    tableEnd();
}

template<typename ForwardIterator>
bool PorridgeDB::writeTable(ForwardIterator first,
                            ForwardIterator last) const
{
    size_t sessionID = boost::lexical_cast<size_t>(m_tableID);
    while(first != last)
        (*(first++))->write(sessionID, this, maxBufferSize);
}

template<typename InputIterator>
void PorridgeDB::setProcessingQueries(InputIterator first,
                                      InputIterator last)
{
    m_indexator.setProcessingQueries(first, last);
}

}//namespace Porridge

#endif // ECHELONDB_H
